#include "sms.h"
#include "slistmethod-default.h"

/*
*/
static gboolean slistview_get_viter_pos(SListView *view,int id,int *x,int *y);

/*
Static func 
*/

static void slistview_show_highlight(SListView *view,gboolean show)
{
	int visable;
	int x,y;
	
	slistview_get_viter_pos(view,view->view_cur,&x,&y);
	goo_canvas_item_set_simple_transform(view->highlight,x,y,1.0,0);
	
	g_object_get(view->highlight,"visibility",&visable,NULL);
	
	if(show && visable!=GOO_CANVAS_ITEM_VISIBLE && view->active)
		g_object_set(view->highlight,"visibility",GOO_CANVAS_ITEM_VISIBLE,NULL);
	else if(!show && visable != GOO_CANVAS_ITEM_HIDDEN)
		g_object_set(view->highlight,"visibility",GOO_CANVAS_ITEM_HIDDEN,NULL);
	
	if(view->cur_iter && view->method->slistmethod_highlight_iter)
		view->method->slistmethod_highlight_iter(view->cur_iter,show);
}

static void slistview_show_up(SListView *view,gboolean show)
{
	int visable;
	
	g_object_get(view->up,"visibility",&visable,NULL);
	
	if(show&&visable!=GOO_CANVAS_ITEM_VISIBLE)
		g_object_set(view->up,"visibility",GOO_CANVAS_ITEM_VISIBLE,NULL);
	else if(!show && visable != GOO_CANVAS_ITEM_HIDDEN)
		g_object_set(view->up,"visibility",GOO_CANVAS_ITEM_HIDDEN,NULL);
}

static void slistview_show_down(SListView *view,gboolean show)
{
	int visable;
	g_object_get(view->down,"visibility",&visable,NULL);
	
	if(show&&visable!=GOO_CANVAS_ITEM_VISIBLE)
		g_object_set(view->down,"visibility",GOO_CANVAS_ITEM_VISIBLE,NULL);
	else if(!show && visable != GOO_CANVAS_ITEM_HIDDEN)
		g_object_set(view->down,"visibility",GOO_CANVAS_ITEM_HIDDEN,NULL);
}

static void slistview_update_cavas(SListView *view)
{
	if(!view)
		return;
	slistview_show_up(view,view->list_cur>0);
	slistview_show_down(view,view->list_cur+view->view_count<view->list_count);
	slistview_show_highlight(view,view->list_count>0);
}

static gboolean slistview_get_viter_pos(SListView *view,int id,int *x,int *y)
{
	if(!view)
		return FALSE;
	
	if(x)
		*x=0;

	if(id<0)
	{
		if(y)
			*y=view->item_height*(-1);
	}
	else if(id>view->view_count)
	{
		if(y)
			*y=view->item_height*(view->view_count+1)+
					view->item_border*(view->view_count+1);
	}
	else
	{
		if(y)
			*y=view->item_height*id+view->item_border*id;
	}
	return TRUE;
}

static gboolean slistview_scroll_iter(SListView *view,int scroll)
{
	
	SListIter *tmp;
	int x,y,i;
	
	if(!view || view->list_count<=0)	
		return FALSE;
	
	if(view->method->slistmethod_highlight_iter)
		view->method->slistmethod_highlight_iter(view->cur_iter,FALSE);
	else
		view->cur_iter->highlight=FALSE;

	if(scroll>0)
	{
		tmp=view->cur_iter;
		for(i=0;i<scroll+1;i++)
		{
			if(tmp->next==NULL)
				break;
			tmp=tmp->next;
		}
		view->cur_iter=tmp->prv;
		for(i=0;i<scroll+view->view_count;i++)
		{
			slistview_get_viter_pos(view,view->view_count-i-1,&x,&y);
			if(view->ani_duration>0)
			{
				goo_canvas_item_animate(tmp->cavas,x,y,1.0,
								0,TRUE,view->ani_duration,
								view->ani_step,GOO_CANVAS_ANIMATE_FREEZE);
			}
			else
			{
				goo_canvas_item_set_simple_transform(tmp->cavas,x,y,1.0,0);
			}
			tmp=tmp->prv;
			if(!tmp)
				break;
		}
		
	}
	else
	{
		tmp=view->cur_iter;
		for(i=0;i>scroll-1;i--)
		{
			if(!tmp->prv)
				break;
			tmp=tmp->prv;
		}
		view->cur_iter=tmp->next;
		for(i=0;i<-1*scroll+view->view_count;i++)
		{
			slistview_get_viter_pos(view,i,&x,&y);
			if(view->ani_duration>0)
			{
				goo_canvas_item_animate(tmp->cavas,x,y,1.0,
									0,TRUE,view->ani_duration,
		 							view->ani_step,GOO_CANVAS_ANIMATE_FREEZE);
			}
			else
			{
				goo_canvas_item_set_simple_transform(tmp->cavas,x,y,1.0,0);
			}
			tmp=tmp->next;
			if(!tmp)
				break;
		}
	}

	view->list_cur+=scroll;
	slistview_update_cavas(view);
}
		
static gboolean slistview_scroll_highlight(SListView *view,int scroll)
{
	SListIter *tmp;
	int x,y,i;
	if(!view)	
		return FALSE;

	if(view->method->slistmethod_highlight_iter)
		view->method->slistmethod_highlight_iter(view->cur_iter,FALSE);
	else
		view->cur_iter->highlight=FALSE;

	if(scroll>0)
	{
		tmp=view->cur_iter;
		for(i=0;i<scroll;i++)
			tmp=tmp->next;
		view->cur_iter=tmp;
	}
	else
	{
		tmp=view->cur_iter;
		for(i=0;i>scroll;i--)
			tmp=tmp->prv;
		view->cur_iter=tmp;
	}
	

	view->view_cur+=scroll;
	slistview_get_viter_pos(view,view->view_cur,&x,&y);
	
	if(view->ani_duration>0)
	{
		goo_canvas_item_animate(view->highlight,x,y,1.0,0,TRUE,
					view->ani_duration,view->ani_step,GOO_CANVAS_ANIMATE_FREEZE);
	}
	else
	{
		goo_canvas_item_set_simple_transform(view->highlight,x,y,1.0,0);
	}
	return TRUE;
}

static void slistview_highlight_ani_cb(GooCanvasItem *item,gboolean stopped,gpointer user_data)
{
	SListView *view=user_data;
	slistview_update_cavas(view);
}


/*
********************************************

SListView API

********************************************
*/

SListView *slistview_new(GooCanvasItem *parent,int x,int y,int width,int item_height,int item_border,int view_count,Theme *theme)
{
	SListView *view;
	view=(SListView *)g_malloc0(sizeof(SListView)+1);
	
	slistview_set_method(view,slistview_default_method());

	view->parent=parent;
	
	view->x=x;
	view->y=y;
	view->width=width;
	view->item_height=item_height;
	view->item_border=item_border;
	view->view_count=view_count;

	view->height=item_height*view_count+item_border*(view_count-1);
	view->theme=theme;
	
	view->cavas=goo_canvas_group_new(view->parent,"x",
			(gdouble)x,"y",(gdouble)y,"width",(gdouble)width,
			 "height",(gdouble)view->height, NULL);	
	view->frame=goo_canvas_group_new(view->cavas,NULL);
		
	view->active=TRUE;
	view->ani_duration=SLISTVIEW_ANI_DURATION;
	view->ani_step=SLISTVIEW_ANI_STEP;
	
	return view;
}

void slistview_destroy(SListView *view)
{
	if(!view)
		return;
	
	slistview_clear_list(view);

	if(view->method)
		g_free(view->method);

	if(view->up)
		goo_canvas_item_remove(view->up);
	if(view->down)
		goo_canvas_item_remove(view->down);
	if(view->background)
		goo_canvas_item_remove(view->background);
	if(view->highlight)
		goo_canvas_item_remove(view->highlight);
	if(view->frame)
		goo_canvas_item_remove(view->frame);
	if(view->cavas)
		goo_canvas_item_remove(view->cavas);
}

void slistview_clear_list(SListView *view)
{
	SListIter *iter=view->head;
	SListIter *next;
	int x,y;
	
	if(!view)
		return;

	while(view->head)
	{
		slistview_remove_iter(view,view->head);
	}

	view->view_cur=0;
	view->list_cur=0;
	view->list_count=0;
	
	view->cur_iter=NULL;
	view->head=NULL;
	view->tail=NULL;
	
	//slistview_get_viter_pos(view,0,&x,&y);
	//goo_canvas_item_set_simple_transform(view->highlight,x,y,1.0,0);
	slistview_update_cavas(view);
}

void slistview_set_method(SListView *view,SListMethod *method)
{
	if(!view||!method)
		return;
	if(view->method)
		g_free(view->method);
	view->method=method;
}

SListMethod* slistview_get_method(SListView *view)
{
	return view->method;
}

void slistview_set_pic(SListView *view,GdkPixbuf *bg,GdkPixbuf *hl,GdkPixbuf *up,GdkPixbuf *down)
{
	int x,y;
	GdkPixbuf *tmp;
	if(bg)
	{
		tmp=gdk_pixbuf_scale_simple(bg,view->width,view->height,GDK_INTERP_BILINEAR);
		if(view->background)
			g_object_unref(view->background);
		view->background=goo_canvas_image_new (view->frame, tmp, 0, 0, NULL);	
		g_object_unref(tmp);
	}
	if(hl)
	{
		tmp=gdk_pixbuf_scale_simple(hl,view->width,view->item_height,GDK_INTERP_BILINEAR);
		if(view->highlight)
			g_object_unref(view->highlight);
		view->highlight=goo_canvas_image_new (view->frame, tmp, 0, 0, NULL);	
		g_object_unref(tmp);
		g_object_set(view->highlight,"visibility",GOO_CANVAS_ITEM_HIDDEN,NULL);
		g_signal_connect(view->highlight,"animation-finished",(GCallback) slistview_highlight_ani_cb,view);
	}
	if(up)
	{
		tmp=gdk_pixbuf_scale_simple(up,view->width,view->item_height,GDK_INTERP_BILINEAR);
		if(view->up)
			g_object_unref(view->up);
		slistview_get_viter_pos(view,0,&x,&y);
		view->up=goo_canvas_image_new (view->cavas, tmp, x, y, NULL);	
		g_object_unref(tmp);
		g_object_set(view->up,"visibility",GOO_CANVAS_ITEM_HIDDEN,NULL);
	}
	if(down)
	{
		tmp=gdk_pixbuf_scale_simple(down,view->width,view->item_height,GDK_INTERP_BILINEAR);
		if(view->down)
			g_object_unref(view->down);
		slistview_get_viter_pos(view,view->view_count-1,&x,&y);
		view->down=goo_canvas_image_new (view->cavas, tmp, x,y, NULL);	
		g_object_unref(tmp);
		g_object_set(view->down,"visibility",GOO_CANVAS_ITEM_HIDDEN,NULL);
	}
}

void slistview_set_pic_by_theme(SListView *view)
{
	Theme *theme=view->theme;
	if(!theme)
		return ;

	slistview_set_pic(view,theme->pic[THEME_PIC_SLISTVIEW_BACKGROUND],
						theme->pic[THEME_PIC_SLISTVIEW_HIGHLIGHT],
						theme->pic[THEME_PIC_SLISTVIEW_UP],
						theme->pic[THEME_PIC_SLISTVIEW_DOWN]);

}

gboolean slistview_scroll(SListView *view,int scroll)
{	
	if(!view || view->list_count<=0)
		return FALSE;
	if(scroll==1)
	{
		if(view->view_cur+view->list_cur==view->list_count-1)
			return FALSE;
		
		if(view->view_cur==view->view_count-2 && view->list_count-view->list_cur-view->view_cur>2)
		{
			return slistview_scroll_iter(view,scroll);
		}
		else if(view->view_cur==view->view_count-1 && view->list_count-view->list_cur-view->view_cur>1)
		{printf("scroll iter\n");
			return slistview_scroll_iter(view,scroll);
		}
		else
		{
			return slistview_scroll_highlight(view,scroll);
		}
	}
	else if(scroll==-1)
	{
		if(view->list_cur==0 && view->view_cur==0)
			return FALSE;
		
		if(view->view_cur==1 && view->list_cur>0)
		{
			return slistview_scroll_iter(view,scroll);
		}
		else
		{
			return slistview_scroll_highlight(view,scroll);
		}
	}
	else
	{
		//FIXME:Just support Scroll 1 row now.
	}
	return FALSE;
}

void slistview_show(SListView *view)
{
	int sit=-1,i=0;
	int x,y;
	
	if(!view || view->list_count<=0)
		return;
	
	SListIter*iter=view->head;
	while(iter)
	{
		if(i==view->list_cur)
			sit=0;
		
		slistview_get_viter_pos(view,sit,&x,&y);
		
		goo_canvas_item_set_simple_transform(iter->cavas,(gdouble)x,
											 (gdouble)y,1.0,0);
		
		//printf("show loop %p,y=%d,sit=%d\n",iter->cavas,y,sit);
		
		iter=iter->next;
		if(sit!=-1)
			sit++;
		i++;
		
	}
	slistview_update_cavas(view);
}

void slistview_set_active(SListView *view,gboolean active)
{
	view->active=active;
	slistview_show_highlight(view,active);
}

void slistview_set_animate(SListView *view,int duration,int step)
{
	if(duration>0)
		view->ani_duration=duration;
	if(step>0&&step<duration)
		view->ani_step=step;
}

/*
SListIter API
*/

SListIter *slistview_append_iter(SListView *view,SListIter*iter)
{
	if(view->tail==NULL)
	{
		view->cur_iter=view->tail=view->head=iter;		
		view->list_count=0;
	}
	else
	{
		iter->prv=view->tail;
		view->tail->next=iter;
		view->tail=iter;
	}
	view->list_count++;
	
	return view->head;
}

SListIter *slistview_prepend_iter(SListView *view,SListIter*iter)
{
	if(view->head==NULL)
	{
		view->cur_iter=view->tail=view->head=iter;		
		view->list_count=0;
	}
	else
	{
		iter->next=view->head;
		view->head->prv=iter;
		view->head=iter;
	}
	view->list_count++;
	
	return view->head;
}

gboolean slistview_remove_iter(SListView *view,SListIter*iter)
{
	if(!iter)
		return FALSE;
	if(view->head==iter)
	{
		if(iter->next!=NULL)
		{
			view->head=iter->next;
			iter->next->prv=NULL;
		}
		else
			view->head=NULL;
	}
	else if(view->tail==iter)
	{
		if(iter->prv!=NULL)
		{
			view->tail=iter->prv;
			iter->prv->next=NULL;
		}
		else
			view->tail=NULL;
	}
	else
	{
		if(!iter->next||!iter->prv)
			return FALSE;
		iter->next->prv=iter->prv;
		iter->prv->next=iter->next;
	}
	
	if(view->cur_iter==iter)
	{
		if(iter->next)
		{
			view->cur_iter=iter->next;
		}
		else if(iter->prv)
		{
			view->cur_iter=iter->prv;
			if(view->list_cur>0)
				view->list_cur--;
			else
				view->view_cur--;
		}
		else
		{
			view->view_cur=0;
			view->list_cur=0;
			view->list_count=0;
	
			view->cur_iter=NULL;
			view->head=NULL;
			view->tail=NULL;
			
			slistview_show_highlight(view,FALSE);
		}
	}

	if(view->method->slistmethod_destroy_iter)
		view->method->slistmethod_destroy_iter(iter);
	else
	{
		if(iter->cavas)
			g_object_unref(iter->cavas);
		g_free(iter);
	}

	view->list_count--;
	return TRUE;
}
	
gboolean slistview_insert_iter(SListView *view,SListIter *iter,gint position)
{
	SListIter*tmp;
	int i;
	
	if(!view||!iter)
		return FALSE;

	if(position>view->list_count||position<=0)
		return  FALSE;
	
	tmp=view->head;

	for(i=0;i<position;i++)
		tmp=tmp->next;

	return slistview_insert_iter_after(view,iter,tmp);
}

gboolean slistview_insert_iter_after(SListView *view,SListIter *iter,SListIter *after)
{
	SListIter *tmp;

	if(!view||!iter||!after)
		return  FALSE;
	
	iter->prv=after;
	iter->next=after->next;
	if(after->next)
		after->next->prv=iter;
	else
		view->tail=iter;
	after->next=iter;
	
	view->list_count++;

	return TRUE;
}

gboolean slistview_insert_iter_before(SListView *view,SListIter *iter,SListIter *before)
{
	SListIter *tmp;

	if(!view||!iter||!before)
		return  FALSE;
	
	iter->next=before;
	iter->prv=before->prv;
	if(before->prv)
		before->prv->next=iter;
	else
		view->head=iter;
	before->prv=iter;
	
	view->list_count++;

	return TRUE;
}

